package com.idea.relax.sensitive.serializer;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.idea.relax.sensitive.annotation.Sensitive;
import com.idea.relax.sensitive.factory.ISensitiveFactory;
import com.idea.relax.sensitive.processor.ISensitiveProcessor;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.IOException;

/**
 * @author salad
 */
@NoArgsConstructor
public class SensitiveSerializer extends JsonSerializer<Object> implements JsonContextualSerializer, ApplicationContextAware {

	private ISensitiveProcessor<Object> processor;

	private static ISensitiveFactory sensitiveFactory;


	public SensitiveSerializer(ISensitiveProcessor<Object> processor) {
		this.processor = processor;
	}

	public static void setSensitiveFactory(ISensitiveFactory sensitiveFactory) {
		SensitiveSerializer.sensitiveFactory = sensitiveFactory;
	}

	@Override
	public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
		gen.writeObject(processor != null ? processor.process(value) : value);
	}

	@Override
	public JsonSerializer<?> getJsonSerializer(SerializerProvider provider, BeanProperty property) throws JsonMappingException {
		Sensitive annotation = getAnnotation(property, Sensitive.class);
		if (null != annotation && null != sensitiveFactory) {
			ISensitiveProcessor<Object> processor = sensitiveFactory.get(annotation.value(), property.getType().getRawClass());
			if (processor != null) {
				return new SensitiveSerializer(processor);
			}
		}
		return provider.findValueSerializer(property.getType(), property);
	}


	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		ObjectProvider<ISensitiveFactory> beanProvider = applicationContext.getBeanProvider(ISensitiveFactory.class);
		beanProvider.ifAvailable(SensitiveSerializer::setSensitiveFactory);
	}

}
